#pragma once
#include "IPlayerCore.h"
#include "DllLib.h"

#define AV_LOG_ERROR 16
#define AV_LOG_INFO 32
#define AV_LOG_VERBOSE 40
#define AV_LOG_SKIP_REPEATED 1
#define AV_LOG_PRINT_LEVEL 2
#define FFMPEG_CORE_VERSION(major, minor, micro, rev) (((int32_t)major << 24) | ((int32_t)minor << 16) | ((int32_t)micro << 8) | (int32_t)rev)
typedef struct MusicHandle MusicHandle;
typedef struct MusicInfoHandle MusicInfoHandle;
typedef struct FfmpegCoreSettings FfmpegCoreSettings;
typedef struct DeviceNameList {
    char* device;
    struct DeviceNameList* prev;
    struct DeviceNameList* next;
} DeviceNameList;
typedef void(*_free_music_handle)(MusicHandle*);
typedef void(*_free_music_info_handle)(MusicInfoHandle*);
typedef void(*_free_ffmpeg_core_settings)(FfmpegCoreSettings*);
typedef void(*_free_device_name_list)(DeviceNameList**);
typedef void(*_ffmpeg_core_free)(void*);
typedef void*(*_ffmpeg_core_malloc)(size_t);
typedef void*(*_ffmpeg_core_realloc)(void*, size_t);
typedef int(*_ffmpeg_core_log_format_line)(void* ptr, int level, const char* fmt, va_list vl, char* line, int line_size, int* print_prefix);
typedef void(*_ffmpeg_core_log_set_callback)(void(*callback)(void*, int, const char*, va_list));
typedef void(*_ffmpeg_core_log_set_flags)(int);
typedef const char*(*_ffmpeg_core_version_str)();
typedef int32_t(*_ffmpeg_core_version)();
typedef int(*_ffmpeg_core_is_wasapi_supported)();
typedef void(*_ffmpeg_core_dump_library_version)(int, int);
typedef void(*_ffmpeg_core_dump_ffmpeg_configuration)(int, int);
typedef int(*_ffmpeg_core_open)(const wchar_t*, MusicHandle**);
typedef int(*_ffmpeg_core_open2)(const wchar_t*, MusicHandle**, FfmpegCoreSettings*);
typedef int(*_ffmpeg_core_open3)(const wchar_t*, MusicHandle**, FfmpegCoreSettings*, const wchar_t*);
typedef int(*_ffmpeg_core_info_open)(const wchar_t*, MusicInfoHandle**);
typedef int(*_ffmpeg_core_play)(MusicHandle*);
typedef int(*_ffmpeg_core_pause)(MusicHandle*);
typedef int(*_ffmpeg_core_seek)(MusicHandle*, int64_t);
typedef int(*_ffmpeg_core_set_volume)(MusicHandle*, int);
typedef int(*_ffmpeg_core_set_speed)(MusicHandle*, float);
typedef int(*_ffmpeg_core_set_equalizer_channel)(MusicHandle*, int, int);
typedef int(*_ffmpeg_core_get_error)(MusicHandle*);
typedef wchar_t*(*_ffmpeg_core_get_err_msg)(int);
typedef const wchar_t*(*_ffmpeg_core_get_err_msg2)(int);
typedef int64_t(*_ffmpeg_core_get_cur_position)(MusicHandle*);
typedef int(*_ffmpeg_core_song_is_over)(MusicHandle*);
typedef int64_t(*_ffmpeg_core_get_song_length)(MusicHandle*);
typedef int64_t(*_ffmpeg_core_info_get_song_length)(MusicInfoHandle*);
typedef int(*_ffmpeg_core_get_channels)(MusicHandle*);
typedef int(*_ffmpeg_core_info_get_channels)(MusicInfoHandle*);
typedef int(*_ffmpeg_core_get_freq)(MusicHandle*);
typedef int(*_ffmpeg_core_info_get_freq)(MusicInfoHandle*);
typedef int(*_ffmpeg_core_is_playing)(MusicHandle*);
typedef int(*_ffmpeg_core_get_bits)(MusicHandle*);
typedef int(*_ffmpeg_core_info_get_bits)(MusicInfoHandle*);
typedef int64_t(*_ffmpeg_core_get_bitrate)(MusicHandle*);
typedef int64_t(*_ffmpeg_core_info_get_bitrate)(MusicInfoHandle*);
typedef wchar_t*(*_ffmpeg_core_get_metadata)(MusicHandle*, const char* key);
typedef wchar_t*(*_ffmpeg_core_info_get_metadata)(MusicInfoHandle*, const char* key);
typedef int(*_ffmpeg_core_get_fft_data)(MusicHandle*, float*, int);
typedef FfmpegCoreSettings*(*_ffmpeg_core_init_settings)();
typedef int(*_ffmpeg_core_settings_set_volume)(FfmpegCoreSettings*, int volume);
typedef int(*_ffmpeg_core_settings_set_speed)(FfmpegCoreSettings*, float);
typedef int(*_ffmpeg_core_settings_set_cache_length)(FfmpegCoreSettings*, int);
typedef int(*_ffmpeg_core_settings_set_max_retry_count)(FfmpegCoreSettings*, int);
typedef int(*_ffmpeg_core_settings_set_url_retry_interval)(FfmpegCoreSettings*, int);
typedef int(*_ffmpeg_core_settings_set_equalizer_channel)(FfmpegCoreSettings*, int, int);
typedef int(*_ffmpeg_core_settings_set_use_WASAPI)(FfmpegCoreSettings*, int);
typedef int(*_ffmpeg_core_settings_set_enable_exclusive)(FfmpegCoreSettings*, int);
typedef int(*_ffmpeg_core_settings_set_max_wait_time)(FfmpegCoreSettings*, int);
typedef DeviceNameList*(*_ffmpeg_core_get_audio_devices)();

class CFfmpegCore : public IPlayerCore, public CDllLib {
public:
    CFfmpegCore();
    ~CFfmpegCore();
    virtual void InitCore() override;
    virtual void UnInitCore() override;
    virtual std::wstring GetAudioType() override;
    virtual int GetChannels() override;
    virtual int GetFReq() override;
    virtual std::wstring GetSoundFontName() override;
    virtual void Open(const wchar_t* file_path) override;
    virtual void Close() override;
    virtual void Play() override;
    virtual void Pause() override;
    virtual void Stop() override;
    virtual void SetVolume(int volume) override;
    virtual void SetSpeed(float speed) override;
    virtual bool SongIsOver() override;
    virtual int GetCurPosition() override;
    virtual int GetSongLength() override;
    virtual void SetCurPosition(int position) override;
    virtual void GetAudioInfo(SongInfo& song_info, int flag = AF_LENGTH | AF_BITRATE | AF_TAG_INFO) override;
    virtual void GetAudioInfo(const wchar_t* file_path, SongInfo& song_info, int flag = AF_LENGTH | AF_BITRATE | AF_TAG_INFO) override;
    virtual bool IsMidi() override;
    virtual bool IsMidiConnotPlay() override;
    virtual MidiInfo GetMidiInfo() override;
    virtual std::wstring GetMidiInnerLyric() override;
    virtual bool MidiNoLyric() override;
    virtual PlayingState GetPlayingState() override;
    virtual void ApplyEqualizer(int channel, int gain) override;
    virtual void SetReverb(int mix, int time) override;
    virtual void ClearReverb() override;
    virtual void GetFFTData(float fft_data[FFT_SAMPLE]) override;
    virtual int GetErrorCode() override;
    virtual std::wstring GetErrorInfo(int error_code) override;
    virtual std::wstring GetErrorInfo() override;
    virtual PlayerCoreType GetCoreType() override;
    std::wstring GetTitle(MusicInfoHandle* h = nullptr);
    std::wstring GetArtist(MusicInfoHandle* h = nullptr);
    std::wstring GetAlbum(MusicInfoHandle* h = nullptr);
    std::wstring GetComment(MusicInfoHandle* h = nullptr);
    std::wstring GetGenre(MusicInfoHandle* h = nullptr);
    std::wstring GetDate(MusicInfoHandle* h = nullptr);
    unsigned short GetYear(MusicInfoHandle* h = nullptr);
    std::wstring GetTrack(MusicInfoHandle* h = nullptr);
    int GetTrackNum(MusicInfoHandle* h = nullptr);
    void UpdateSettings();
    void SetCacheLength(int cache_length = 15);
    void SetMaxRetryCount(int max_retry_count = 3);
    void SetUrlRetryInterval(int url_retry_interval = 5);
    std::list<std::wstring> GetAudioDevices();
    int32_t GetVersion();
    bool IsWASAPISupported();
    void EnableWASAPI(bool enable);
    void EnableExclusiveMode(bool enable);
    void SetMaxWaitTime(int max_wait_time = 3000);

    virtual bool EncodeAudio(SongInfo song_info, const wstring& dest_file_path, EncodeFormat encode_format, void* encode_para, int dest_freq, EncodeAudioProc proc) override;
    virtual bool InitEncoder() override;
    virtual void UnInitEncoder() override;
    virtual bool IsFreqConvertAvailable() override;

private:
    std::wstring GetMetadata(std::string key, MusicInfoHandle* h = nullptr);
    virtual bool GetFunction() override;
    static void LogCallback(void*, int, const char*, va_list);
    _free_music_handle free_music_handle = nullptr;
    _free_music_info_handle free_music_info_handle = nullptr;
    _free_ffmpeg_core_settings free_ffmpeg_core_settings = nullptr;
    _free_device_name_list free_device_name_list = nullptr;
    _ffmpeg_core_free ffmpeg_core_free = nullptr;
    _ffmpeg_core_malloc ffmpeg_core_malloc = nullptr;
    _ffmpeg_core_realloc ffmpeg_core_realloc = nullptr;
    _ffmpeg_core_log_format_line ffmpeg_core_log_format_line = nullptr;
    _ffmpeg_core_log_set_callback ffmpeg_core_log_set_callback = nullptr;
    _ffmpeg_core_log_set_flags ffmpeg_core_log_set_flags = nullptr;
    _ffmpeg_core_version_str ffmpeg_core_version_str = nullptr;
    _ffmpeg_core_version ffmpeg_core_version = nullptr;
    _ffmpeg_core_is_wasapi_supported ffmpeg_core_is_wasapi_supported = nullptr;
    _ffmpeg_core_dump_library_version ffmpeg_core_dump_library_version = nullptr;
    _ffmpeg_core_dump_ffmpeg_configuration ffmpeg_core_dump_ffmpeg_configuration = nullptr;
    _ffmpeg_core_open ffmpeg_core_open = nullptr;
    _ffmpeg_core_open2 ffmpeg_core_open2 = nullptr;
    _ffmpeg_core_open3 ffmpeg_core_open3 = nullptr;
    _ffmpeg_core_info_open ffmpeg_core_info_open = nullptr;
    _ffmpeg_core_play ffmpeg_core_play = nullptr;
    _ffmpeg_core_pause ffmpeg_core_pause = nullptr;
    _ffmpeg_core_seek ffmpeg_core_seek = nullptr;
    _ffmpeg_core_set_volume ffmpeg_core_set_volume = nullptr;
    _ffmpeg_core_set_speed ffmpeg_core_set_speed = nullptr;
    _ffmpeg_core_set_equalizer_channel ffmpeg_core_set_equalizer_channel = nullptr;
    _ffmpeg_core_get_error ffmpeg_core_get_error = nullptr;
    _ffmpeg_core_get_err_msg ffmpeg_core_get_err_msg = nullptr;
    _ffmpeg_core_get_err_msg2 ffmpeg_core_get_err_msg2 = nullptr;
    _ffmpeg_core_get_cur_position ffmpeg_core_get_cur_position = nullptr;
    _ffmpeg_core_song_is_over ffmpeg_core_song_is_over = nullptr;
    _ffmpeg_core_get_song_length ffmpeg_core_get_song_length = nullptr;
    _ffmpeg_core_info_get_song_length ffmpeg_core_info_get_song_length = nullptr;
    _ffmpeg_core_get_channels ffmpeg_core_get_channels = nullptr;
    _ffmpeg_core_info_get_channels ffmpeg_core_info_get_channels = nullptr;
    _ffmpeg_core_get_freq ffmpeg_core_get_freq = nullptr;
    _ffmpeg_core_info_get_freq ffmpeg_core_info_get_freq = nullptr;
    _ffmpeg_core_is_playing ffmpeg_core_is_playing = nullptr;
    _ffmpeg_core_get_bits ffmpeg_core_get_bits = nullptr;
    _ffmpeg_core_info_get_bits ffmpeg_core_info_get_bits = nullptr;
    _ffmpeg_core_get_bitrate ffmpeg_core_get_bitrate = nullptr;
    _ffmpeg_core_info_get_bitrate ffmpeg_core_info_get_bitrate = nullptr;
    _ffmpeg_core_get_metadata ffmpeg_core_get_metadata = nullptr;
    _ffmpeg_core_info_get_metadata ffmpeg_core_info_get_metadata = nullptr;
    _ffmpeg_core_get_fft_data ffmpeg_core_get_fft_data = nullptr;
    _ffmpeg_core_init_settings ffmpeg_core_init_settings = nullptr;
    _ffmpeg_core_settings_set_volume ffmpeg_core_settings_set_volume = nullptr;
    _ffmpeg_core_settings_set_speed ffmpeg_core_settings_set_speed = nullptr;
    _ffmpeg_core_settings_set_cache_length ffmpeg_core_settings_set_cache_length = nullptr;
    _ffmpeg_core_settings_set_max_retry_count ffmpeg_core_settings_set_max_retry_count = nullptr;
    _ffmpeg_core_settings_set_url_retry_interval ffmpeg_core_settings_set_url_retry_interval = nullptr;
    _ffmpeg_core_settings_set_equalizer_channel ffmpeg_core_settings_set_equalizer_channel = nullptr;
    _ffmpeg_core_settings_set_use_WASAPI ffmpeg_core_settings_set_use_WASAPI = nullptr;
    _ffmpeg_core_settings_set_enable_exclusive ffmpeg_core_settings_set_enable_exclusive = nullptr;
    _ffmpeg_core_settings_set_max_wait_time ffmpeg_core_settings_set_max_wait_time = nullptr;
    _ffmpeg_core_get_audio_devices ffmpeg_core_get_audio_devices = nullptr;
    int GetEqChannelFreq(int channel);
    MusicHandle* handle;
    FfmpegCoreSettings* settings = nullptr;
    std::wstring recent_file;
    int err;
    int32_t version;
};
